package com.dingwen.treasure.auth.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import com.dingwen.treasure.base.constant.RedisConstant;
import com.dingwen.treasure.common.redis.service.RedisService;
import com.dingwen.treasure.jwt.config.JwtProperties;
import com.dingwen.treasure.jwt.constant.JwtConstant;
import com.dingwen.treasure.jwt.uitl.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 　TokenService: 令牌服务
 * 　@author dingwen
 * 　@since  2022/6/12
 */
@Service
@Slf4j
public class TokenService {

    /**
     * jwt 配置信息
     */
    @Resource
    private JwtProperties jwtProperties;


    /**
     * jwt 工具
     */
    @Resource
    private JwtUtil jwtUtil;

    /**
     * redis 服务
     */
    @Resource
    private RedisService redisService;


    /**
     * 通过 token 获取登录的用户信息
     *
     * @param token 令牌
     * @return
     */
    public JSONObject getLoginUser(String token) {
        // 缓存获取 +
        // redis key(USER:userId)
        String key = getKeyByLoginUser(token);
        return redisService.getCacheObject(key);
    }


    /**
     * 缓存登录用户信息： 默认5分钟
     *
     * @param loginUser 登录用户
     */
    public void setLoginUser(JSONObject loginUser) {
        String userId = String.valueOf(loginUser.getObj(JwtConstant.USER_ID));
        String key = RedisConstant.LOGIN_USER_KEY.concat(userId);
        redisService.setCacheObject(key, loginUser, jwtProperties.getAppExpireTime(), TimeUnit.MINUTES);
    }

    /**
     * 通过 token 获取登录的用户信息
     *
     * @param request 请求
     * @return {@link JSONObject}
     */
    public JSONObject getLoginUser(HttpServletRequest request) {
        // token
        String token = getToken(request);
        return getLoginUser(token);
    }


    /**
     * 通过 token 获取 redis key （用户）
     *
     * @param token 令牌
     * @return {@link String}
     */
    public String getKeyByLoginUser(String token) {
        Claims claims = jwtUtil.verify(token);
        String userId = getValue(claims, JwtConstant.USER_ID);
        return RedisConstant.LOGIN_USER_KEY.concat(userId);
    }

    /**
     * 根据数据声明信息获取键值
     *
     * @param claims 数据声明信息
     * @param key    键
     * @return 值
     */
    public static String getValue(Claims claims, String key) {
        return Convert.toStr(claims.get(key), "");
    }


    /**
     * 通过请求获取令牌
     *
     * @param request 要求
     * @return {@link String}
     */
    public String getToken(HttpServletRequest request) {
        String token = request.getHeader(jwtProperties.getHeader());
        String tokenPrefix = jwtProperties.getTokenPrefix();
        if (StringUtils.isNotEmpty(token) && token.startsWith(tokenPrefix)) {
            token = token.replace(tokenPrefix.concat(" "), "");
        }
        return token;
    }


    /**
     * 生成web令牌
     *
     * @param userId  用户id
     * @param account 账号
     * @return {@link String}
     */
    public String generateWebToken(String userId, String account) {
        Map<String, Object> claims = generateClaims(userId, account);
        claims.put(JwtConstant.TOKEN_TYPE, JwtConstant.WEB_TOKEN);
        String token = jwtUtil.generate(claims);
        String key = getKeyByToken(userId);
        redisService.setCacheObject(key, token, jwtProperties.getWebExpireTime(), TimeUnit.MINUTES);
        return token;
    }

    /**
     * 获取token缓存key
     *
     * @param userId 用户id
     * @return {@link String}
     */
    public String getKeyByToken(String userId) {
        return RedisConstant.TOKEN_KEY.concat(userId);
    }

    /**
     * 生成app令牌
     *
     * @param userId  用户id
     * @param account 账号
     * @return {@link String}
     */
    public String generateAppToken(String userId, String account) {
        Map<String, Object> claims = generateClaims(userId, account);
        claims.put(JwtConstant.TOKEN_TYPE, JwtConstant.APP_TOKEN);
        String token = jwtUtil.generate(claims);
        String key = getKeyByToken(userId);
        redisService.setCacheObject(key, token, jwtProperties.getAppExpireTime(), TimeUnit.MINUTES);
        return token;
    }

    /**
     * 生成基础数据项
     *
     * @param userId  用户id
     * @param account 账号
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    public Map<String, Object> generateClaims(String userId, String account) {
        HashMap<String, Object> claims = MapUtil.newHashMap(4);
        claims.put(JwtConstant.USER_ID, userId);
        claims.put(JwtConstant.ACCOUNT, account);
        return claims;
    }
}


